package model.param;

import domain.RawDataDO;
import lombok.Data;

import java.util.LinkedList;
import java.util.List;
import java.util.Objects;

/**
 * @author 刀氏春秋
 * @date 2023/6/16
 */
@Data
public class CombineParam {
    private String hostAssetNo;
    List<Expression> expressions = new LinkedList<>();

    /**
     * 检查是否为非法数据点
     * 判断依据是电流或电压值是否为空
     *
     * @param point 参考数据点
     * @return 数据值
     */
    private boolean isInvalidPoint(Point point) {
        return point.getVoltage() == null || (point.getCurrent() == null);
    }

    /**
     * 设置组合式多元线性回归参数
     *
     * @param host   主表
     * @param custom 从表
     */
    public void setParams(RawDataDO host, RawDataDO custom) {
        // 获取主从表数据点列表
        List<Point> hostPoints = host.getPoints();
        List<Point> customPoints = custom.getPoints();
        for (int i = 0; i < hostPoints.size(); i++) {
            // 获取主从表数据点
            Point hostPoint = hostPoints.get(i);
            Point customPoint = customPoints.get(i);
            // 此步排除空值点
            if (isInvalidPoint(hostPoint) || isInvalidPoint(customPoint))
                continue;
            // 对于非空值点，将其引入到expression中
            this.expressions.add(new Expression(
                    hostPoint.getVoltage(), customPoint.getVoltage(), customPoint.getCurrent(), hostPoint.getCurrent()));
        }
    }

    /**
     * 检查表数据电流是否为0
     *
     * @return 返回0代表一切正常，数据不全为0；返回1代表主表电流值全为0；
     * 返回2代表从表电流值全为0，返回3代表两表电流值均全为0
     */
    private Integer checkCurrentIsAllZero() {
        int countHostCurrent = 0;
        int countCustomCurrent = 0;
        for (Expression expression : this.expressions) {
            // 仅需判断一个即可，单个表达式组的单相表数据是相同的
            if (expression.getXi() > 1e-5) {
                countHostCurrent++;
            }
            if (expression.getXI() > 1e-5) {
                countCustomCurrent++;
            }
        }

        if (countHostCurrent != 0 && countCustomCurrent != 0) {
            // 二者均不全零，返回0
            return 0;
        } else if (countHostCurrent == 0 && countCustomCurrent != 0) {
            // 主表电流全零，返回1
            return 1;
        } else if (countHostCurrent != 0) {
            // 从表电流全零，返回2
            return 2;
        } else {
            // 主表从表全零，返回3
            return 3;
        }
    }

    /**
     * 导出Y值
     *
     * @return 算法参数Y列向量
     */
    public double[] getY() {
        double[] y = new double[expressions.size()];
        for (int i = 0; i < y.length; i++) {
            y[i] = expressions.get(i).getY();
        }
        return y;
    }

    /**
     * 导出x矩阵
     *
     * @return 算法参数x矩阵
     */
    public double[][] getX() {
        double[][] x = null;
        Integer situation = checkCurrentIsAllZero();
        // 判断情形，并初始化x矩阵
        switch (situation) {
            case 0 -> {
                x = new double[expressions.size()][3];
            }
            case 1, 2 -> {
                x = new double[expressions.size()][2];
            }
            case 3 -> {
                x = new double[expressions.size()][1];
            }
        }
        // 将expression数据导出到x矩阵当中
        for (int i = 0; i < Objects.requireNonNull(x).length; i++) {
            switch (situation) {
                // 主从表数据齐全，正常带入
                case 0 -> {
                    x[i][0] = expressions.get(i).getXV();
                    x[i][1] = expressions.get(i).getXI();
                    x[i][2] = expressions.get(i).getXi();
                }
                // 主表数据不齐全，只代入从表数据
                case 1 -> {
                    x[i][0] = expressions.get(i).getXV();
                    x[i][1] = expressions.get(i).getXI();
                }
                // 从表数据不齐全，只代入主表数据
                case 2 -> {
                    x[i][0] = expressions.get(i).getXV();
                    x[i][1] = expressions.get(i).getXi();
                }
                // 主从表数据全都不齐，只代入一个从表电压即可
                case 3 -> {
                    x[i][0] = expressions.get(i).getXV();
                }
            }
        }
        return x;
    }
}
